﻿/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#ifndef __3B827C21_D00B_4693_8624_F1626FB7F6E3__
#define __3B827C21_D00B_4693_8624_F1626FB7F6E3__

#include "../release/head.h"
#include "com_declare.h"
#include "i_unknown.h"
#include <vector>
#include <string>

/////////////////////////////////////////////////////////////////////////////////////////
// 
namespace xos
{
    // 
    // unknown_impl
    // 
    template < class CHILD, class OBJ, class LOCK >
    class unknown_impl : public release_impl< OBJ >
    {
    public:
        typedef release_impl< OBJ > BASE;

    public:
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //
        unknown_impl( i_unknown * pOutterUnknown = 0 ) : BASE(), __xos_com_interface_map_entry(0), __xos_class_name_array_ptr(0),
            __xos_outter_unknown_ptr( pOutterUnknown ),
            _xos_n_ref( 1 )
        {
        }
        ~unknown_impl()
        {
            if( __xos_com_interface_map_entry )
            {
                delete [] __xos_com_interface_map_entry;
                __xos_com_interface_map_entry = 0;
            }
            if( __xos_class_name_array_ptr )
            {
                delete __xos_class_name_array_ptr;
                __xos_class_name_array_ptr = 0;
            }
        }
    public:
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //
        int query_interface( const char * iid, void ** ppv )
        {
            int ret = 0;
            if( get_outter_unknown() )
            {
                ret = get_outter_unknown()->query_interface( iid, ppv );
            }
            else
            {
                ret = xos_internal_query_interface( this, BASE::_xos_get_interface_entries(), iid, ppv );
                if( 0 == ret )
                {
                    ret = add_ref();
                }
            }
            return ret;
        }
        int add_ref()
        {
            int ret = 0;
            if( get_outter_unknown() )
            {
                ret = get_outter_unknown()->add_ref();
            }
            else
            {
                CHILD * pT = static_cast< CHILD * >( this );
                ret = pT->final_add_ref();
            }
            return ret;
        }
        int release()
        {
            int ret = 0;
            if( get_outter_unknown() )
            {
                ret = get_outter_unknown()->release();
            }
            else
            {
                CHILD * pT = static_cast< CHILD * >( this );
                ret = pT->final_sub_ref();
                if( 0 == ret )
                {
                    ret = BASE::release();
                }
            }
            return ret;
        }
    public:
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //
        const _XOS_COM_INTERFACE_MAP_ENTRY * xos_com_interface_map_entry( const _XOS_COM_INTERFACE_MAP_ENTRY * pEntry, int nNum )
        {
            if( !__xos_com_interface_map_entry && pEntry )
            {
                __xos_com_interface_map_entry = new _XOS_COM_INTERFACE_MAP_ENTRY[nNum];
                for( int i = 0; i < nNum; ++i )
                {
                    __xos_com_interface_map_entry[i] = pEntry[i];
                }
            }
            return __xos_com_interface_map_entry;
        }
    public:
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //
        int xos_collect_com_obj_class_name( const char * lpszClassName )
        {
            if( !__xos_class_name_array_ptr )
            {
                __xos_class_name_array_ptr  = new std::vector< std::string >;
            }
            __xos_class_name_array_ptr->push_back( lpszClassName );
            return 0;
        }
        const char * query_creatable_class_name( int nIndex )
        {
            const char * pRet = 0;
            if( nIndex < ( int )__xos_class_name_array_ptr->size() )
            {
                pRet = __xos_class_name_array_ptr->at( nIndex ).c_str();
            }
            return pRet;
        }
        bool xos_has_collect_class_name()
        {
            return 0 != __xos_class_name_array_ptr;
        }
    public:
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 支持聚合
        int set_outter_unknown( i_unknown * pOutterUnknown )
        {
            __xos_outter_unknown_ptr = pOutterUnknown;
            return 0;
        }
        i_unknown * get_outter_unknown()
        {
            return __xos_outter_unknown_ptr;
        }
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        // 给unknown_impl使用
        int final_add_ref()
        {
            int ret = 0;
            _xos_thread_lock.lock();
            ret = ++_xos_n_ref;
            _xos_thread_lock.un_lock();
            return ret;
        }
        int final_sub_ref()
        {
            int ret = 0;
            _xos_thread_lock.lock();
            ret = --_xos_n_ref;
            _xos_thread_lock.un_lock();
            return ret;
        }
    public:
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //
        int init()
        {
            int ret = 0;
            if( 0 == ret )
            {
                ret = BASE::init();
            }
            return ret;
        }
        int term()
        {
            int ret = 0;
            __xos_outter_unknown_ptr = 0;
            _xos_n_ref = 1;
            BASE::term();
            return ret;
        }
    private:
        ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        //
        _XOS_COM_INTERFACE_MAP_ENTRY * __xos_com_interface_map_entry;
        std::vector< std::string > * __xos_class_name_array_ptr;
        i_unknown * __xos_outter_unknown_ptr;
        LOCK _xos_thread_lock;
        int _xos_n_ref;
    };
}

#endif // __3B827C21_D00B_4693_8624_F1626FB7F6E3__
